package survivalstagegenerator;

import java.io.IOException;
import java.io.FileWriter;
import java.io.File;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SurvivalStage {
	private final static int NUMBER_OF_PHASES = 100;
	private String stageSourceCode;
	private ArrayList<Phase> phases;
	private int difficulty;
	private int bossPhaseQuantity;
	private int boundValue;
	private final int BOSS_PHASE_BONUS = 400;
	// Any value below 780 for bound will result in a stage, where one cannot
	// progress towards the right.
	private final int MINIMAL_PHASE_BOUND = 780;
	private final static int DATA_ID = 50;

//    private final int FIRST_LEVEL_PHASE_BOUND = 1000;
//    private final int SECOND_LEVEL_PHASE_BOUND = 1200;
//    private final int THIRD_LEVEL_PHASE_BOUND = 1500;
//    private final int FOURTH_LEVEL_PHASE_BOUND = 1800;
//    private final int FIFTH_LEVEL_PHASE_BOUND = 2000;
//    private final int DIFFICULTY_ZERO_MAX_STRENGTH_INIT = 200;

//    private final int DIFFICULTY_ONE_MAX_STRENGTH_INIT = 300;
//    private final int DIFFICULTY_TWO_MAX_STRENGTH_INIT = 400;
//    private final int DIFFICULTY_THREE_MAX_STRENGTH_INIT = 500;
//    private final int DIFFICULTY_FOUR_MAX_STRENGTH_INIT = 600;

	public SurvivalStage() {
		this.stageSourceCode = "";
		this.phases = new ArrayList<Phase>();
		this.difficulty = -1;
		this.bossPhaseQuantity = 10;
		this.boundValue = 800;
	}

	public void createSurvivalStage(final int difficulty, final int bossPhaseQuantity, final int boundValue) {
		this.difficulty = difficulty;
		this.bossPhaseQuantity = bossPhaseQuantity;
		if (boundValue <= MINIMAL_PHASE_BOUND) {
			Logger.getLogger(SurvivalStage.class.getName()).log(Level.SEVERE, null,
					"Bound value too low: " + boundValue);
			System.exit(1);
		}
		this.boundValue = boundValue;
		this.phases = this.generateSurvivalStage();
	}

	private ArrayList<Phase> generateSurvivalStage() {
		int phaseIndex = 0;
		while (true) {
			// break at the 100th stage
			if (phaseIndex >= SurvivalStage.NUMBER_OF_PHASES) {
				break;
			}

			System.out.println("\nPhase:" + phaseIndex);
			final int phaseStrength = this.calculatePhaseStrength(phaseIndex);
			if (phaseIndex % this.bossPhaseQuantity == 0 && phaseIndex != 0) {
				final ArrayList<Phase> phases = this.phases;
				phases.add((Phase) new BossPhase(phaseStrength + this.BOSS_PHASE_BONUS, this.boundValue,
						"phase " + Integer.toString(phaseIndex) + " boss phase"));
			} else {
				this.phases.add(new Phase(phaseStrength, this.boundValue, "phase " + Integer.toString(phaseIndex)));
			}
			this.phases.get(phaseIndex).generatePhase();
			++phaseIndex;
		}
		return this.phases;
	}

	/**
	 * Serialize the survival stage into actual survival stage source code, which
	 * can be added to stage.dat using some LF2 data changer.
	 * 
	 * @return source code of a survival stage
	 */
	public String getSurvivalStageSourceCode() {
		this.stageSourceCode += "<stage> id: " + SurvivalStage.DATA_ID + "  #Survival Stage\n";
		for (int phaseIndex = 0; phaseIndex < this.phases.size(); ++phaseIndex) {
			this.stageSourceCode += this.phases.get(phaseIndex).getPhaseSourceCode();
			
			// If this is the last phases, then add a repeat of phases.
			if (phaseIndex == SurvivalStage.NUMBER_OF_PHASES - 1) {
				final int pos = this.stageSourceCode.lastIndexOf(60);
				final String str1 = this.stageSourceCode.substring(0, pos);
				final String str2 = this.stageSourceCode.substring(pos, this.stageSourceCode.length());
				this.stageSourceCode = str1 + "\twhen_clear_goto_phase: 90\n\t" + str2;
			}
		}
		return this.stageSourceCode;
	}

	private int calculatePhaseStrength(final int phaseCounter) {
		final int initPhaseStrength = 100 + (this.difficulty * 100);
		final int increasePerPhase = 100; 
		final int increasePerPassedBossPhase = 200;
		
		// Higher phases should be more difficult, so calculate an added 
		// phases strength depending on the phase index.
		final int increaseForPhase = phaseCounter * increasePerPhase;
		
		// Each passed boss phase should add some difficulty for all following 
		// phases.
		final int passedBossPhases = phaseCounter / this.bossPhaseQuantity;
		final int increaseForPassedBossPhases = passedBossPhases * increasePerPassedBossPhase;
		
		final int resultStrength = initPhaseStrength + increaseForPassedBossPhases + increaseForPhase;
		System.out.println("Maximum strength:" + resultStrength);
		return resultStrength;
	}

	public void saveStage() throws IOException {
		final String filename = "Stage.txt";
		final File nf = new File(filename);
		final FileWriter writer = new FileWriter(nf);
		try {
			writer.write(this.getSurvivalStageSourceCode());
			writer.append(System.getProperty("line.seperator"));
			writer.flush();
			writer.close();
		} catch (IOException err) {
			Logger.getLogger(SurvivalStage.class.getName()).log(Level.SEVERE, null, err);
			System.out.println("Program encountered an error while trying to write to file " + filename);
		}
	}
}
